#pragma link "cgauges"
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "Globals.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}

//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::FormCreate(TObject *Sender)
{ // Get the working directory
  getcwd( dirc, MAXPATH );

  // Memory for RAM
  ram = ( BYTE *)malloc( 0x20000 );
  if ( !ram )
  {
    ShowMessage( "Fatal Error: Could not allocate needed memory for RAM." );
    Close( );
  }

  //
  vmText->Clear( );
  vmPointers->Clear( );
  vms.Pointer = NULL;

  isRunning = false;  
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
  _free( rom.data );
  _free( ram );
  exit( 0 );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::Dumpallscriptstotextfiles1Click(TObject *Sender)
{
  TVMS TEMP;
  FILE *tf;

  int  index;
  char FileName[512];
  char buf[256];
/*
  if ( !rom.data ) return;
  //
  TEMP  = vms;
  index = -1;
  // TRY to run current script
//  vmText->Lines->BeginUpdate( );
//  vmTextData = "";
  //
//  vmText->Clear( );
  // Clear label refs
  KanaForm->KanaMemo->Lines->BeginUpdate( );
  memset( vms.LabelRef, 0, (rom.Length - rom.Header) );
  //
  CGBar->MaxValue = vmPointers->Items->Count;
  CGBar->Progress = 0;
  //
  while( ++index < vmPointers->Items->Count )
  { //
    isRunning = true;
    //---------------------//
    // Get the pointer nfo //
    //---------------------//
    strcpy( buf, vmPointers->Items->Strings[ index ].c_str( ) );
    sscanf( buf, "%X %X", &vms.Start, &vms.End );
    //--------------------------
    vms.Start      = Snes2Pc( vms.Start );
    vms.End        = Snes2Pc( rom.Length );
    //
    vms.LabelRef[ vms.Start ] |= 0x80;
    //
    vms.Pointer    = &rom.data[ vms.Start ];
    vms.BaseOffset = vms.Start;
    // Adjust the offsets to be 'RELATIVE' addresses
    vms.End       -= vms.Start;
    vms.Start      = 0;
    //--------------------------
    //
    while( isRunning )
    {
      if ( VirtuaMachineDump( ) == -1 ) isRunning = false;
      CheckMSG( );
    }
    //
    CGBar->Progress = index;
  }

  //-------------------------
  index = -1;
  while( ++index < vmPointers->Items->Count )
  { //
    strcpy( buf, vmPointers->Items->Strings[ index ].c_str( ) );
    sscanf( buf, "%X %X", &vms.Start, &vms.End );
    //--------------------------
    vms.Start      = Snes2Pc( vms.Start );
    //--------------------------
    vms.LabelRef[ vms.Start ] |= 0x80;
  }

  //------------------------------------//
  // Dump what was found!               //
  //------------------------------------//
  // Save the file
/*  tf = fopen( "ScriptDump.txt", "wt" );
  //
  if ( !tf )
  { //
    ShowMessage( "Error: Could not open file for dumping!" );
    KanaForm->KanaMemo->Lines->EndUpdate( );
    fcloseall( );
    return;
  }
//
  //
  KanaForm->KanaMemo->Lines->SaveToFile( "ScriptDump.txt" );
  //
  fcloseall( );
  KanaForm->KanaMemo->Lines->EndUpdate( );
  ShowMessage( "File was created!" );
  //
  vms             = TEMP;
  CGBar->Progress = 0;
*/  
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::SaveTexttoafile1Click( TObject *Sender )
{
  char Message[256];
  int  k;

  if ( FSave1->Execute( ) )
  {
    if ( FileExists( FSave1->FileName ) )
    { //
      sprintf( Message, "\"%s\" already exist.\nReplace this file?", FSave1->FileName.c_str( ) );
      //
      k = Application->MessageBox( Message, "Save text data to a file", MB_YESNO + MB_ICONQUESTION );
      if ( k == IDYES ) goto _CanSave_;
    }
    else
    { //
      _CanSave_:
      vmText->Lines->SaveToFile( FSave1->FileName );
    } // END IF
  }
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::OpenROMfile1Click(TObject *Sender)
{
  FILE *rf;

  FOpen1->InitialDir = dirc;
  FOpen1->FileName   = "";
  FOpen1->Filter     = "Snes ROM File|*.s?c;*.fig";
  //
  if ( FOpen1->Execute( ) )
  { //
    strcpy( romf, FOpen1->FileName.c_str( ) );
    rf = fopen( romf, "rb" );
    if ( !rf )
    {
      ShowMessage( "Error: Could not open the ROM file." );
      fcloseall( );
      return;
    }
    //
    _free( rom.data );
    rom.Length   = FileSize( rf );
    rom.Header   = ( rom.Length & 0x0200 );
    rom.data     = ( BYTE *)malloc( ( rom.Length - rom.Header ) );
    vms.LabelRef = ( BYTE *)malloc( ( rom.Length - rom.Header ) << 1 );
    //
    if ( !rom.data || !vms.LabelRef )
    {
      ShowMessage( "Fatal Error: Could not allocate needed memory for ROM file." );
      fcloseall( );
      Close( );
      return;
    }
    //
    fseek( rf, rom.Header, SEEK_SET );
    fread( rom.data, 1, ( rom.Length - rom.Header ), rf );
    memset( vms.LabelRef, 0, (rom.Length - rom.Header) );
    // Test for the correct ROM
    if ( strncmp( &rom.data[0xFFC0], "FARLANDSTORY2", 13 ) )
    { //
      ShowMessage( "Error: This is NOT the correct ROM file." );
      _free( rom.data );
      fcloseall( );
      return;
    }
    //
    fclose( rf );
    //
    OpenTablefile1Click( Sender );
    OpenPointerFile1Click( Sender );    
  }
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::OpenTablefile1Click(TObject *Sender)
{
  char buf[256];
  FILE *rf;

  FOpen1->InitialDir = dirc;
  FOpen1->FileName   = "";
  FOpen1->Filter     = "TABLE File|*.tbl";
  //
  if ( FOpen1->Execute( ) )
  { //
    strcpy( tblf, FOpen1->FileName.c_str( ) );
    rf = fopen( tblf, "rt" );
    if ( !rf )
    {
      ShowMessage( "Error: Could not open the TABLE file." );
      fcloseall( );
      return;
    }

    // Load up table data
    while( fgets( buf, 255, rf ) )
    { //
      strcpy( buf, Trim( AnsiString( buf ) ).c_str( ) );
      //
      if ( buf[2] == '=' )
      { //
        buf[2] = 0;
        strcpy( tbl.sngl[ strtoul( buf, NULL, 16 ) ], &buf[3] );
      }
      else
      if ( buf[4] == '=' )
      { //
        buf[4] = 0;
        strcpy( tbl.dual[ strtoul( buf, NULL, 16 ) ], &buf[5] );
      }
    }
    //
    fclose( rf );
  }
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::OpenPointerFile1Click(TObject *Sender)
{
  char buf[256];
  char arg1[32];
  char arg2[32];
  //
  FILE *rf;

  //------------------------
  if ( !rom.data )
  {
    ShowMessage( "Please load a ROM file before continuing." );
    return;
  }
  //------------------------
  FOpen1->InitialDir = dirc;
  FOpen1->FileName   = "";
  FOpen1->Filter     = "Pointer TEXT File|*.txt";
  //
  if ( FOpen1->Execute( ) )
  { //
    strcpy( txtf, FOpen1->FileName.c_str( ) );
    rf = fopen( txtf, "rt" );
    if ( !rf )
    {
      ShowMessage( "Error: Could not open the TEXT file." );
      fcloseall( );
      return;
    }
    //
    vmPointers->Clear( );
    vmPointers->Items->BeginUpdate( );
    while( fgets( buf, 255, rf ) )
    {
      strcpy( buf, Trim( AnsiString( buf ) ).c_str( ) );
      if ( !buf[0] || buf[0] == ';' || buf[0] == '/' )
        continue;
      //  
      memset( arg1, 0, 16 );
      memset( arg2, 0, 16 );
      sscanf( buf, "%s %s", &arg1, &arg2 );
      //
      sprintf( buf, "%s %8c %s", arg1, ' ', arg2 );
      vmPointers->Items->Add( Trim( AnsiString( buf ) ) );
    }
    //
    vmPointers->Items->EndUpdate( );
    //
    vms.curIndex          = 0;
    vmPointers->ItemIndex = 0;
    //
    strcpy( buf, vmPointers->Items->Strings[ vms.curIndex ].c_str( ) );
    sscanf( buf, "%X %X", &vms.Start, &vms.End );
    //--------------------------
    vms.Start      = Snes2Pc( vms.Start );
//      vms.End        = Snes2Pc( vms.End );
    vms.End        = Snes2Pc( rom.Length );
    //
    vms.Pointer    = &rom.data[ vms.Start ];
    vms.BaseOffset = vms.Start;
    // Adjust the offsets to be 'RELATIVE' addresses
    vms.End       -= vms.Start;
    vms.Start      = 0;
    //
    fclose( rf );

    Form1->Caption = "Farland Story 2: Virtual Machine - " + IntToStr( vmPointers->Items->Count ) + " Script pointer(s)";
  }
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
  Close( );
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::Step1Click(TObject *Sender)
{
  if ( !vms.Pointer ) return;
  // Step through BYTE CODE
  isRunning = false;
  //
  VirtuaMachine( );
  //
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::Run1Click(TObject *Sender)
{
  if ( !vms.Pointer ) return;
  // TRY to run current script
  isRunning = true;
  //
  vmText->Clear( );
  // Clear label refs
  memset( vms.LabelRef, 0, (rom.Length - rom.Header) );

  vmText->Lines->BeginUpdate( );
  KanaForm->KanaMemo->Lines->BeginUpdate( );
  vmTextData = "";
  //-----------------------------//
  // First pass gets ALL offsets //
  // Pointed to by script code.  //
  //-----------------------------//
  while( isRunning )
  {
    if ( VirtuaMachine( ) == -1 ) isRunning = false;
    CheckMSG( );
  }
  //
  vmText->Text = vmTextData;
  KanaForm->KanaMemo->Lines->EndUpdate( );
  vmText->Lines->EndUpdate( );
  CGBar->Progress = 0;
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::vmPointersDblClick(TObject *Sender)
{
  char buf[256];

  if ( !rom.data ) return;
  //
  for ( int c = 0; c < vmPointers->Items->Count; c++ )
  {
    if ( vmPointers->Selected[ c ] )
    { // Clear All sub pointers
      vmText->Clear( );
      vms.curIndex = c;
      // Clear label refs
      memset( vms.LabelRef, 0, (rom.Length - rom.Header) );
      //
      strcpy( buf, vmPointers->Items->Strings[ vms.curIndex ].c_str( ) );
      sscanf( buf, "%X %X", &vms.Start, &vms.End );
      //--------------------------
      vms.Start      = Snes2Pc( vms.Start );
//      vms.End        = Snes2Pc( vms.End );
      vms.End        = Snes2Pc( rom.Length );
      //
      vms.Pointer    = &rom.data[ vms.Start ];
      vms.BaseOffset = vms.Start;
      // Adjust the offsets to be 'RELATIVE' addresses
      vms.End       -= vms.Start;
      vms.Start      = 0;
      //
      KanaForm->Caption = "Kana Strings - Loading...";
      KanaForm->KanaMemo->Clear( );
      Run1Click( Sender );
      KanaForm->Caption = "Kana Strings";
      //
      break;
    } // END IF
  }
}


//------------------------------//
//                              //
//------------------------------//
LONG __fastcall TForm1::VirtuaMachine( )
{
  char buf[512];
  BYTE index      = 0;
  LONG value      = 0;
  LONG lpOffset;
  LONG count;

  static AnsiString vmNameData;

  // If done, leave routine
  if ( vms.Start >= vms.End )
    return -1;
  //
  // Check to see if we can place a LABEL here
  if ( vms.LabelRef[ (vms.BaseOffset + vms.Start) ] )
  {
    vmTextData = vmTextData + AnsiString( "\r\n" );
//    vmTextData = vmTextData + AnsiString( ";************************;\r\n" );
//    vmTextData = vmTextData + AnsiString( "; Declared Pointer Label ;\r\n" );
//    vmTextData = vmTextData + AnsiString( ";************************;\r\n" );
    if ( vms.LabelRef[ (vms.BaseOffset + vms.Start) ] == 1 )
      vmTextData = vmTextData + AnsiString( "_Label_" + IntToHex( 0xC00000 | (vms.BaseOffset + vms.Start) , 8 ) + ":\r\n" );
    else
      vmTextData = vmTextData + AnsiString( "_Script_" + IntToHex( 0xC00000 | (vms.BaseOffset + vms.Start) , 8 ) + ":\r\n" );
  }

  //-----------------------------//
  //                             //
  //-----------------------------//
  vms.opCode = *(WORD *)&vms.Pointer[ vms.Start ];
  vms.Start += 2;
  //
  switch( vms.opCode )
  { //
    case 0xFFFF : vmTextData = vmTextData + AnsiString( ".ENDCODE[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  return -1; // End of script
    //---------------------------------//
    // 0 byte codes                    //
    //---------------------------------//
    case 0x0000 : // No args   ; Reset game
    case 0x0001 : // No args
    case 0x0002 : // No args
    case 0x0003 : // No args
    case 0x0005 : // No args
    case 0x0006 : // No args   ; Clear Textmap Buffer?
    case 0x0007 : // No args
    case 0x0008 : // No args
    case 0x0009 : // No args
    case 0x000A : // No args
    case 0x000B : // No args
    case 0x000E : // No args   ; Fadein??
    case 0x000F : // No args   ; Fadeout??
    case 0x0010 : // No args
    case 0x0011 : // No args
    case 0x0012 : // BYTES
    case 0x0013 : // 1 BYTE
    case 0x0015 : // No args
    case 0x001A : // No args
    case 0x001B : // No args
    case 0x001C : // No args
    case 0x001D : // No args
    case 0x002E : // No args
    case 0x002F : // No args
    case 0x0030 : // No args
    case 0x0031 : // No args
    case 0x0034 : // No args
    case 0x0035 : // No args
    case 0x0036 : // No args
    case 0x0037 : // No args
    case 0x0038 : // No args
    case 0x0039 : // No args
    case 0x003A : // No args
    case 0x003B : // No args
    case 0x0023 : // No args   ; Scroll screen?
    case 0x0045 : // No args
    case 0x0046 : // No args
    case 0x0047 : // No args
    case 0x003E : // No args
    case 0x003F : // No args
    case 0x0040 : vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  break; // 0 bytes
    //---------------------------------//
    // 1 byte codes                    //
    //---------------------------------//
    case 0x0014 : // 1 BYTE
    case 0x0016 : // 1 BYTE    ; screen flashed white
    case 0x0017 : // 1 BYTE
    case 0x0018 : // 1 BYTE
    case 0x0019 : // 1 BYTE
    case 0x0021 : // 1 BYTE
    case 0x0022 : // 1 BYTE
    case 0x002C : // 1 BYTE
    case 0x002D : // 1 BYTE
    case 0x0032 : // 1 BYTE
    case 0x0033 : // 1 BYTE
    case 0x0043 : // 1 BYTE
    case 0x0044 : // 1 BYTE
    case 0x0055 :
    case 0x0056 : vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + IntToHex( vms.Pointer[ vms.Start ], 2 ) + "]\r\n" );
                  vms.Start += 1; break; // 1 byte
    //---------------------------------//
    // 2 byte codes                    //
    //---------------------------------//
    case 0x0004 : // 2 BYTES
    case 0x000C : // 2 BYTES
    case 0x000D : // 2 BYTES
    case 0x001E : // 2 BYTES
    case 0x0024 : // 2 BYTES
    case 0x0025 : // 2 BYTES
    case 0x002A : // 2 BYTES
    case 0x002B : vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 2 ) + "]\r\n" );
                  vms.Start += 2; break; // 2 bytes

    //---------------------------------//
    // 3 byte codes                    //
    //---------------------------------//
    case 0x0028 : // 3 BYTES
    case 0x0029 : vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 3 ) + "]\r\n" );
                  vms.Start += 3; break; // 3 bytes
    //---------------------------------//
    // 4 byte codes                    //
    //---------------------------------//
    case 0x001F : // 4 BYTES
    case 0x0020 : vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 4 ) + "]\r\n" );
                  vms.Start += 4; break; // 3 bytes
    //---------------- THIS AREA NEEDS WORK ----------------
    case 0x0026 :
    case 0x0027 : vmTextData = vmTextData + AnsiString( ".DATA[$" + IntToHex( vms.opCode, 4 ) + "]    // N.P.C. Movement Values\r\n" );
                  while( vms.Pointer[ vms.Start ] != 0xFF && vms.Start < vms.End )
                    vmTextData = vmTextData + AnsiString( "  [$" + IntToHex( vms.Pointer[ vms.Start++ ], 2 ) + "]\r\n" );
                  //
                  vmTextData = vmTextData + AnsiString( ".ENDDATA[$" + HexStr( vms.Start , 2 )+ "]\r\n" );
                  vms.Start += 2;
                  break;
    //---------------- THIS AREA NEEDS WORK ----------------
    case 0x003C : // Text Pointers, Upper Textbox
    case 0x003D : // Text Pointers, Lower Textbox
    case 0x0041 : // Text Pointers, Center Textbox
                  vmTextData = vmTextData + AnsiString( "\r\n" );
                  vmTextData = vmTextData + AnsiString( "//*****************************//\r\n" );
                  vmTextData = vmTextData + AnsiString( "// Open Dialogue Session       //\r\n" );
                  vmTextData = vmTextData + AnsiString( "//*****************************//\r\n" );
                  //
                  value = GET24( vms.Pointer, vms.Start );
                  if ( value < 0xC00000 )
                    vmTextData = vmTextData + AnsiString( "/**** POINTER ERROR: OFFSET: " + IntToHex( vms.Start, 8 ) + " ****/\r\n" );
                  //--------------------------------------
                  if ( vms.opCode == 0x3C ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.UPPER  _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
                  if ( vms.opCode == 0x3D ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.LOWER  _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
                  if ( vms.opCode == 0x41 ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.CENTER _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
                  // Display the text to the form if not there already
                  if ( !(vms.LabelRef[ Snes2Pc( value ) ] & 0x01) )
                    DecodeTextData( Snes2Pc( value ) );

                  // Save the offset for a ref to write out a label
                  vms.LabelRef[ Snes2Pc( value ) ] |= 1;
                  vms.Start += 3;
                  break;     // 3 BYTES     ; Upper, lower, Clear Textbox?? @ 24-bit Text pointer
    // Unknown Pointer, record for now
    case 0x0042 : value = GET24( vms.Pointer, vms.Start );
                  if ( value < 0xC00000 )
                    vmTextData = vmTextData + AnsiString( "/**** POINTER ERROR: OFFSET: " + IntToHex( vms.Start, 8 ) + " ****/\r\n" );
                  //--------------------------------------
                  vmTextData = vmTextData + AnsiString( ".POINTER[$0042] _Label_" + IntToHex( value , 8 ) + "\r\n" );
                  // Save the offset for a ref to write out a label
//                  vms.LabelRef[ Snes2Pc( value ) ] = 1;
                  vms.Start += 3; break;     // 3 BYTES     ; unknown?? @ 24-bit pointer
    //---------------------------------
    case 0x0054 : vmTextData = vmTextData + AnsiString( ".JMP _Script_" + HexStr( vms.Start, 3 ) + "\r\n" );
                  vms.Start += 3; break; // 3 bytes
    //--------------------------------
    case 0x004A : // 4 BYTES     ; 1 BYTE - test, 3 BYTE - Script Call Offset
    case 0x004B : // 4 BYTES
    case 0x004D : // 4 BYTES
    case 0x0057 : // 4 BYTES
    case 0x0058 : // 4 BYTES
    case 0x0048 : // 4 BYTES
    case 0x0049 : // 4 BYTES
    case 0x004C : vmTextData = vmTextData + AnsiString( ".CMP[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 1 ) + "] "
                  ".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 1 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 4; break;     // Varies, Could be a "control statement" code
    //--------------------------------
    case 0x004E : // Varies, Could be a "control statement" code
    case 0x004F : vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 4 ) + "] "
                  ".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 4 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 7; break;     //  Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0050 : // Varies, Could be a "control statement" code
    case 0x0051 : vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 6 ) + "] "
                  ".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 6 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 9; break;     // 6 bytes, Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0052 : // Varies, Could be a "control statement" code
    case 0x0053 : vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 2 ) + "] "
                  ".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 2 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 5; break;     // Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0059 : vmTextData = vmTextData + AnsiString( ".ENDSCRIPT[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  return -1; // break;
    default     : vmTextData = vmTextData + AnsiString( ".INVALID OPCODE [$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  break; // 0 bytes - Invald opCode
  }

  return vms.Start;
}


//------------------------------//
//                              //
//------------------------------//
AnsiString __fastcall TForm1::HexStr( LONG lpOffset, LONG lpCount )
{
  AnsiString Temp = "";

  for ( int c = 0; c < lpCount; c++ )
    Temp = Temp + AnsiString( IntToHex( vms.Pointer[ lpOffset + c ], 2 ) );
  //
  return Temp;
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::FindInternalScripts1Click(TObject *Sender)
{
  FILE *pf,
       *sf;

  TVMS TEMP;

  int  index;
  char FileName[512];
  char buf[256];

  if ( !rom.data ) return;
  //

  TEMP  = vms;
  index = -1;
  // TRY to run current script
  vmText->Lines->BeginUpdate( );
  KanaForm->KanaMemo->Lines->BeginUpdate( );
  //
  KanaForm->KanaMemo->Text = "";
  vmTextData = "";
  //
  vmText->Clear( );
  // Clear label refs
  memset( vms.LabelRef, 0, (rom.Length - rom.Header) );
  //
  CGBar->MaxValue = vmPointers->Items->Count;
  CGBar->Progress = 0;
  //
  while( ++index < vmPointers->Items->Count )
  { //
    isRunning = true;
    //---------------------//
    // Get the pointer nfo //
    //---------------------//
    strcpy( buf, vmPointers->Items->Strings[ index ].c_str( ) );
    sscanf( buf, "%X %X", &vms.Start, &vms.End );
    //--------------------------
    vms.Start      = Snes2Pc( vms.Start );
    vms.End        = Snes2Pc( rom.Length );
    //
    vms.LabelRef[ vms.Start ] |= 0x80;
    //
    vms.Pointer    = &rom.data[ vms.Start ];
    vms.BaseOffset = vms.Start;
    // Adjust the offsets to be 'RELATIVE' addresses
    vms.End       -= vms.Start;
    vms.Start      = 0;
    //--------------------------
    //
    while( isRunning )
    {
      if ( VirtuaMachineDump( ) == -1 ) isRunning = false;
      CheckMSG( );
    }
    //
    CGBar->Progress = index;
  }

  //-------------------------
  index = -1;
  while( ++index < vmPointers->Items->Count )
  { //
    strcpy( buf, vmPointers->Items->Strings[ index ].c_str( ) );
    sscanf( buf, "%X %X", &vms.Start, &vms.End );
    //--------------------------
    vms.Start      = Snes2Pc( vms.Start );
    //--------------------------
    vms.LabelRef[ vms.Start ] |= 0x80;
  }

  //------------------------------------//
  // Dump what was found!               //
  //------------------------------------//
  // Save the file
  sf = fopen( "Scripts.txt", "wt" );
  pf = fopen( "Pointers.txt", "wt" );
  //
  if ( !pf || !sf )
  { //
    ShowMessage( "Error: Could notopen files for dumping!" );
    fcloseall( );
    return;
  }

  //
  int  cString = 0;
  for ( LONG c = 0; c < rom.Length; c++ )
  {
//    if ( (vms.LabelRef[ c ] & 0x01) ) fprintf( pf, "(%Xh)String_%d\n", c, cString++ );
    if ( (vms.LabelRef[ c ] & 0x02) && !(vms.LabelRef[ c ] & 0x80) ) fprintf( sf, ".SCRIPT  %08X\n", c );
  }
  //
  fcloseall( );
  KanaForm->KanaMemo->Lines->SaveToFile( "Pointers.txt" );
  //
  ShowMessage( "Files were dumped!" );
  //
  vmText->Clear( );
  KanaForm->KanaMemo->Clear( );
  vmText->Lines->EndUpdate( );
  KanaForm->KanaMemo->Lines->EndUpdate( );
  //
  vms = TEMP;
  CGBar->Progress = 0;
}


//------------------------------//
//                              //
//------------------------------//
void __fastcall TForm1::DecodeTextData( LONG lpOffset )
{
  LONG posi;
  WORD *Pointer;
  WORD data;
  char buf[64];

  (BYTE *)Pointer = &rom.data[ lpOffset ];

  KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( "//***********************//\r\n"
                                                                    "// Kana to be translated //\r\n"
                                                                    "//***********************//\r\n" );
  KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( "_Label_" + IntToHex( 0xC00000 | (lpOffset) , 8 ) + ":\r\n ; " );
  //-----------------------------//
  //                             //
  //-----------------------------//
  posi = 0;
  data = Pointer[ posi ];
  while( data != 0xFFFF )
  { //---------------//
    // Control Codes //
    //---------------//
    data = Pointer[ posi++ ];
    //
    if ( (data & 0xF000) == 0x8000 )
    { //
      switch( data )
      { // End Text
        case 0x8000: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "\r\n"
                                                                           "\r\n//***************************//"
                                                                           "\r\n// Translated text goes here //"
                                                                           "\r\n//***************************//"
                                                                           "\r\n.TRANS\r\n\r\n.ENDT\r\n\r\n";
                     data = 0xFFFF;  break;
        // Newline
        case 0x8001: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "\r\n ; "; break;
        //
//        case 0x8002:
        //
//        case 0x8003:
        //
//        case 0x8004:
        //
//        case 0x8005:
        // 8x16 text
        case 0x8006: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "[8x16]"; break;
        // 16x16 text
        case 0x8007: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "[16x16]"; break;
        //
//        case 0x8008:
        //
//        case 0x8009:
        //
//        case 0x800A:
        //
//        case 0x800B:
        // Keypress
        case 0x800C: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "[Key]"; break;
        // TextXY
        case 0x800D: sprintf( buf, "[Text: X=%04X, Y=%04X]", Pointer[ posi + 0 ], Pointer[ posi + 1 ] );
                     KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( buf );
                     posi += 2; break;
        //
//        case 0x800E:
        // Clear Screen
        case 0x800F: KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + "[Clrs]\r\n ; "; break;
        //--------------------------------
        default    : KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( "[$" + IntToHex( data, 4 ) + "]" ); break;
      }
    }
    else
    { //-----------------------------//
      // Dump table data             //
      //-----------------------------//
      data = ( data >> 8 ) | ( (data & 0xFF) << 8 );
      //
      if ( tbl.dual[ data ][0] )
      { // Dump the text
        KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( tbl.dual[ data ] );
        data = 0;
      }
      else
      {
        KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( "[$" + IntToHex( data, 4 ) + "]" );
        data = 0;
      }
    } // END IF
  } // END WHILE
}


//-----------------------------//
//                             //
//-----------------------------//
void __fastcall TForm1::DisplayKanaData1Click(TObject *Sender)
{
  KanaForm->Show( );
}



//------------------------------//
//                              //
//------------------------------//
LONG __fastcall TForm1::VirtuaMachineDump( )
{
  char buf[512];
  BYTE index      = 0;
  LONG value      = 0;
  LONG lpOffset;
  LONG count;

  // If done, leave routine
  if ( vms.Start >= vms.End ) return -1;

  //-----------------------------//
  //                             //
  //-----------------------------//
  vms.opCode = *(WORD *)&vms.Pointer[ vms.Start ];
  vms.Start += 2;
  //
  switch( vms.opCode )
  { //
    case 0xFFFF : //vmTextData = vmTextData + AnsiString( ".ENDCODE[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  return -1; // End of script
    //---------------------------------//
    // 0 byte codes                    //
    //---------------------------------//
    case 0x0000 : // No args   ; Reset game
    case 0x0001 : // No args
    case 0x0002 : // No args
    case 0x0003 : // No args
    case 0x0005 : // No args
    case 0x0006 : // No args   ; Clear Textmap Buffer?
    case 0x0007 : // No args
    case 0x0008 : // No args
    case 0x0009 : // No args
    case 0x000A : // No args
    case 0x000B : // No args
    case 0x000E : // No args   ; Fadein??
    case 0x000F : // No args   ; Fadeout??
    case 0x0010 : // No args
    case 0x0011 : // No args
    case 0x0012 : // BYTES
    case 0x0013 : // 1 BYTE
    case 0x0015 : // No args
    case 0x001A : // No args
    case 0x001B : // No args
    case 0x001C : // No args
    case 0x001D : // No args
    case 0x002E : // No args
    case 0x002F : // No args
    case 0x0030 : // No args
    case 0x0031 : // No args
    case 0x0034 : // No args
    case 0x0035 : // No args
    case 0x0036 : // No args
    case 0x0037 : // No args
    case 0x0038 : // No args
    case 0x0039 : // No args
    case 0x003A : // No args
    case 0x003B : // No args
    case 0x0023 : // No args   ; Scroll screen?
    case 0x0045 : // No args
    case 0x0046 : // No args
    case 0x0047 : // No args
    case 0x003E : // No args
    case 0x003F : // No args
    case 0x0040 : //vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  break; // 0 bytes
    //---------------------------------//
    // 1 byte codes                    //
    //---------------------------------//
    case 0x0014 : // 1 BYTE
    case 0x0016 : // 1 BYTE    ; screen flashed white
    case 0x0017 : // 1 BYTE
    case 0x0018 : // 1 BYTE
    case 0x0019 : // 1 BYTE
    case 0x0021 : // 1 BYTE
    case 0x0022 : // 1 BYTE
    case 0x002C : // 1 BYTE
    case 0x002D : // 1 BYTE
    case 0x0032 : // 1 BYTE
    case 0x0033 : // 1 BYTE
    case 0x0043 : // 1 BYTE
    case 0x0044 : // 1 BYTE
    case 0x0055 :
    case 0x0056 : //vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + IntToHex( vms.Pointer[ vms.Start ], 2 ) + "]\r\n" );
                  vms.Start += 1; break; // 1 byte
    //---------------------------------//
    // 2 byte codes                    //
    //---------------------------------//
    case 0x0004 : // 2 BYTES
    case 0x000C : // 2 BYTES
    case 0x000D : // 2 BYTES
    case 0x001E : // 2 BYTES
    case 0x0024 : // 2 BYTES
    case 0x0025 : // 2 BYTES
    case 0x002A : // 2 BYTES
    case 0x002B : //vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 2 ) + "]\r\n" );
                  vms.Start += 2; break; // 2 bytes

    //---------------------------------//
    // 3 byte codes                    //
    //---------------------------------//
    case 0x0028 : // 3 BYTES
    case 0x0029 : //vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 3 ) + "]\r\n" );
                  vms.Start += 3; break; // 3 bytes
    //---------------------------------//
    // 4 byte codes                    //
    //---------------------------------//
    case 0x001F : // 4 BYTES
    case 0x0020 : //vmTextData = vmTextData + AnsiString( ".OPCODE[$" + IntToHex( vms.opCode, 4 ) + "].USE [$" + HexStr( vms.Start, 4 ) + "]\r\n" );
                  vms.Start += 4; break; // 3 bytes
    //---------------- THIS AREA NEEDS WORK ----------------
    case 0x0026 :
    case 0x0027 : // vmTextData = vmTextData + AnsiString( ".DATA[$" + IntToHex( vms.opCode, 4 ) + "]    // N.P.C. Movement Values\r\n" );
                  while( vms.Pointer[ vms.Start ] != 0xFF && vms.Start < vms.End )
                    vms.Start++;
                  //
                  vms.Start += 2;
                  break;
    //---------------- THIS AREA NEEDS WORK ----------------
    case 0x003C : // Text Pointers, Upper Textbox
    case 0x003D : // Text Pointers, Lower Textbox
    case 0x0041 : // Text Pointers, Center Textbox
//                  vmTextData = vmTextData + AnsiString( "\r\n" );
//                  vmTextData = vmTextData + AnsiString( "//*****************************//\r\n" );
//                  vmTextData = vmTextData + AnsiString( "// Open Dialogue Session       //\r\n" );
//                  vmTextData = vmTextData + AnsiString( "//*****************************//\r\n" );
                  //
                  value = GET24( vms.Pointer, vms.Start );
//                  if ( value < 0xC00000 )
//                    vmTextData = vmTextData + AnsiString( "/**** POINTER ERROR: OFFSET: " + IntToHex( vms.Start, 8 ) + " ****/\r\n" );
                  //--------------------------------------
//                  if ( vms.opCode == 0x3C ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.UPPER  _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
//                  if ( vms.opCode == 0x3D ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.LOWER  _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
//                  if ( vms.opCode == 0x41 ) vmTextData = vmTextData + AnsiString( ".TEXTBOX.CENTER _Label_" + IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + "\r\n" );
                  // Display the text to the form if not there already
//                  if ( !(vms.LabelRef[ Snes2Pc( value ) ] & 0x01) )  DecodeTextData( Snes2Pc( value ) );
                  // Save the offset for a ref to write out a label
                  KanaForm->KanaMemo->Text = KanaForm->KanaMemo->Text + AnsiString( ".POINTER " +
                    IntToHex( value = GET24( vms.Pointer, vms.Start ), 8 ) + " @ " +
                    IntToHex( (vms.Start + vms.BaseOffset), 8 ) + " \r\n"
                  );
                  //
                  vms.LabelRef[ Snes2Pc( value ) ] |= 1;
                  vms.Start += 3;
                  break;     // 3 BYTES     ; Upper, lower, Clear Textbox?? @ 24-bit Text pointer
    // Unknown Pointer, record for now
    case 0x0042 : //value = GET24( vms.Pointer, vms.Start );
//                  if ( value < 0xC00000 )
//                    vmTextData = vmTextData + AnsiString( "/**** POINTER ERROR: OFFSET: " + IntToHex( vms.Start, 8 ) + " ****/\r\n" );
                  //--------------------------------------
//                  vmTextData = vmTextData + AnsiString( ".POINTER[$0042] _Label_" + IntToHex( value , 8 ) + "\r\n" );
                  // Save the offset for a ref to write out a label
//                  vms.LabelRef[ Snes2Pc( value ) ] = 1;
                  vms.Start += 3; break;     // 3 BYTES     ; unknown?? @ 24-bit pointer
    //---------------------------------
    case 0x0054 : //vmTextData = vmTextData + AnsiString( ".JMP _Script_" + HexStr( vms.Start, 3 ) + "\r\n" );
                  vms.Start += 3; break; // 3 bytes
    //--------------------------------
    case 0x004A : // 4 BYTES     ; 1 BYTE - test, 3 BYTE - Script Call Offset
    case 0x004B : // 4 BYTES
    case 0x004D : // 4 BYTES
    case 0x0057 : // 4 BYTES
    case 0x0058 : // 4 BYTES
    case 0x0048 : // 4 BYTES
    case 0x0049 : // 4 BYTES
    case 0x004C : //vmTextData = vmTextData + AnsiString( ".CMP[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 1 ) + "] "
                  //".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 1 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  //vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 4; break;     // Varies, Could be a "control statement" code
    //--------------------------------
    case 0x004E : // Varies, Could be a "control statement" code
    case 0x004F : //vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 4 ) + "] "
                  //".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 4 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  //vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 7; break;     //  Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0050 : // Varies, Could be a "control statement" code
    case 0x0051 : //vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 6 ) + "] "
                  //".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 6 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  //vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 9; break;     // 6 bytes, Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0052 : // Varies, Could be a "control statement" code
    case 0x0053 : //vmTextData = vmTextData + AnsiString( ".TEST[$" + IntToHex( vms.opCode, 4 ) + "] [$" + HexStr( vms.Start, 2 ) + "] "
                  //".GOTO _Script_" + IntToHex( value = GET24(vms.Pointer, vms.Start + 2 ), 8 ) + "\r\n" );
                  // Save the offset to record as a label
                  //vms.LabelRef[ Snes2Pc( value ) ] |= 2;
                  vms.Start += 5; break;     // Varies, Could be a "control statement" code
    //--------------------------------
    case 0x0059 : //vmTextData = vmTextData + AnsiString( ".ENDSCRIPT[$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  return -1; // break;
    default     : //vmTextData = vmTextData + AnsiString( ".INVALID OPCODE [$" + IntToHex( vms.opCode, 4 ) + "]\r\n" );
                  break; // 0 bytes - Invald opCode
  }

  return vms.Start;
}

